package cn.devhost;

import cn.hutool.core.io.IoUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @author shenguangyang
 */
@Slf4j
public class HostUtils {
    private static final String HOSTS_PATH = "C:\\Windows\\System32\\drivers\\etc\\hosts";
    private static final String ENDL = String.format("%n");

    public static Set<String> read() throws IOException {
        return Arrays.stream(IoUtil.read(Files.newInputStream(Paths.get(HOSTS_PATH), StandardOpenOption.READ),  StandardCharsets.UTF_8).split(ENDL))
                .filter(it->!it.trim().matches("(^#.*)|(\\s*)"))
                .map(it->it.replaceAll("#.*", "").trim().replaceAll("\\s+", "\t"))
                .collect(Collectors.toSet());
    }

    public static boolean append(String ip, String url) throws IOException {
        Set<String> sets = HostUtils.read();
        Map<String, String> map = new HashMap<>();
        sets.forEach(e -> {
            String[] split = e.split("\t");
            map.put(split[1], split[0]);
        });
        map.put(url, ip);
        sets = map.entrySet()
                .stream().map(e -> String.format("%s\t%s", e.getValue(), e.getKey())).collect(Collectors.toSet());
        IoUtil.write(Files.newOutputStream(Paths.get(HOSTS_PATH), StandardOpenOption.WRITE), StandardCharsets.UTF_8, true, String.join(ENDL, sets));
        return flushDns();
    }

    public static boolean exists(String ip, String url) throws IOException {
        return HostUtils.read().contains(String.format("%s\t%s", ip, url));
    }

    public static boolean flushDns() {
        try {
            Runtime.getRuntime().exec("ipconfig /flushdns");
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    public static ServerInfo getCurrentServerInfo() {
        String ip;
        String hostname;
        try {
            InetAddress addr = InetAddress.getLocalHost();
            ip = addr.getHostAddress();
            hostname = addr.getHostName();
        } catch (UnknownHostException e) {
            log.error("Can't find out address: " + e.getMessage());
            ip = "UNKNOWN";
            hostname = "UNKNOWN";
        }
        if (ip.equals("127.0.0.1") || ip.equals("::1") || ip.equals("UNKNOWN")) {
            try {
                Process process = Runtime.getRuntime().exec("hostname -i");
                if (process.waitFor() == 0) {
                    ip = new String(IOUtils.toByteArray(process.getInputStream()), StandardCharsets.UTF_8);
                }
                process = Runtime.getRuntime().exec("hostname");
                if (process.waitFor() == 0) {
                    hostname = (new String(IOUtils.toByteArray(process.getInputStream()), StandardCharsets.UTF_8)).trim();
                }
            } catch (Exception e) {
                log.warn("get hostname failed {}", e.getMessage());
            }
        }
        return ServerInfo.builder().ip(ip).hostname(hostname).build();
    }

    public static void main(String[] args) {
        int nThreads = 1;
        ExecutorService executorService = Executors.newCachedThreadPool();
        while (nThreads-- > 0) {
            executorService.execute(()->{
                boolean rst = false;
                try {
                    rst = HostUtils.append("1.2.0.0", "www.baidu.com");
                    System.out.println(rst);
                    HostUtils.read().forEach(System.out::println);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

            });
        }
        executorService.shutdown();
    }
}
